﻿using System;
using System.Text;
using RoughJs.Ast;
using System.IO;

namespace RoughJsConsole
{
    public class Shell : ScriptableObject
    {

        public void Run()
        {
            
            //在当前线程创建上下文
            Context cx = Context.enter();
            //Shell shell = new Shell();
            //创始化一个标准对象
            cx.initStandardObjects(this);
            String[] names = { "alert","load" };
            this.defineFunctionProperties(names, typeof(Shell),
                                          ScriptableObject.DONTENUM);



           // String source = "";
            //  source = @"var ab =1+(5*3) ; alert('ab '+ab); var d = ab+1; alert(d);";//变量赋值
           // StringBuilder script = new StringBuilder(1024);
            //script.Append(@"a =3+5 ,b =2 ; if(a>b) alert(a+'>'+b);else alert(a+'<'+b);");
            //script.Append(@"function a1(t){ alert(t);} a1(a);");
            //script.Append(@" c=5;while(c>0){alert('c:::'+c);c--;}");
            //script.Append(@"for(var i =b;i<a;i++) alert('i:'+i); ");
            //script.Append(@" function uu(){ return 111;}  alert(uu());");
            //script.Append(@" function test1(t1,t2){ return t1+t2;};  alert(test1(2,6));");
            //script.Append(@" var u = function(){ return 1234;}; ");
            //script.Append(@" alert(u());");

            //script.Append("var n =2; switch(n){case 1: alert('1'); break; case 2:alert('2') }");
            //script.Append(@"var t; alert(t);");
            //script.Append(@" var iNum=10; alert(iNum.toString(2));");//测试字符串
            //script.Append(" var a=new Array(); a[1.23]=\"test\"; alert(a[1.23]); alert(a.length);");
            //script.Append(@" var b=new Array(5,4,3,'first','test,string'); alert(b[0]);");//测试数组
            //script.Append(@" alert(null == undefined);");
            //script.Append(@" alert(typeof 'aa')");

            //script.Append("var n = 0; var obj = {toLocaleString: function() {n++}}; var myArray = [obj, obj, obj]; alert(myArray.toLocaleString());");
            //script.Append(createTry());
            //source = script.ToString();

            //bool isFile = true;
            //if (isFile)
            //{
            //    String filename = @"H:\脚本程序\JavaScript\示例\e4x3.js";
            //    ReadFile(cx, shell, filename);
            //}
            //else
            //{
            //    ConsoleFile(cx, shell, source);
            //}
            this.processSource(cx,  null);
        }

        private static bool isEditor = false;//如果是编辑器打开 为true,如果不是为false

        static void Main(string[] args)
        {
            //try
            //{
            //    Context cx = Context.enter();
            //    cx.setLanguageVersion(Context.VERSION_1_7);
            //    Shell shell1 = new Shell();
            //    cx.initStandardObjects(shell1);
            //    String[] names = { "alert", "load" };
            //    shell1.defineFunctionProperties(names, typeof(Shell),
            //                                  ScriptableObject.DONTENUM);

            //    StringBuilder source = new StringBuilder();
            //    source.Append("function fib() {\n");
            //    source.Append("var j = 0;\n");
            //    source.Append("while(true){\n");
            //    source.Append("j++;\n");
            //    source.Append("yield j;\n");
                
            //    source.Append("}\n");
            //    source.Append("}\n");
            //    source.Append("var g = fib();alert(g.next());alert(g.next());");
            //    ReadFile(cx, shell1, "d:/le.js");
            //    //ConsoleFile(cx, shell1, source.ToString());
            //}
            //catch (Exception ex)
            //{

            //}

            isEditor = false;
            try
            {
                Shell shell = new Shell();
                if (args.Length <= 0 || args == null)
                {

                    shell.Run();
                }
                else
                {
                    if (args[0].ToLower().Trim() == "-e")
                    {//说明是编译器在调用
                        isEditor = true;
                        shell.Run();
                    }
                    else
                    {
                        Context cx = Context.enter();

                        //创始化一个标准对象
                        cx.initStandardObjects(shell);
                        String[] names = { "alert", "load" };
                        shell.defineFunctionProperties(names, typeof(Shell),
                                                      ScriptableObject.DONTENUM);
                        String fileName = args[0];
                        //StringBuilder source = new StringBuilder();
                        //source.Append("function fib() {\n");
                        //source.Append("var j = 0;\n");
                        //source.Append("while(true){\n");
                        //source.Append("yield j;\n");
                        //source.Append("j++;\n");
                        //source.Append("}\n");
                        //source.Append("}\n");

                        //ConsoleFile(cx, shell, source.ToString());
                        ReadFile(cx, shell, fileName);
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }



            ////////////////////////////////////////////////////////////////////////////////////////////////////////


        //    //在当前线程创建上下文
        //    Context cx = Context.enter();
        //    Shell shell = new Shell();
        //    //创始化一个标准对象
        //    cx.initStandardObjects(shell);
        //    String[] names = { "alert","load" };
        //    shell.defineFunctionProperties(names, typeof(Shell),
        //                                  ScriptableObject.DONTENUM);



        //    String source = "";
        //    //  source = @"var ab =1+(5*3) ; alert('ab '+ab); var d = ab+1; alert(d);";//变量赋值
        //    StringBuilder script = new StringBuilder(1024);
        //    //script.Append(@"a =3+5 ,b =2 ; if(a>b) alert(a+'>'+b);else alert(a+'<'+b);");
        //    //script.Append(@"function a1(t){ alert(t);} a1(a);");
        //    //script.Append(@" c=5;while(c>0){alert('c:::'+c);c--;}");
        //    //script.Append(@"for(var i =b;i<a;i++) alert('i:'+i); ");
        //    //script.Append(@" function uu(){ return 111;}  alert(uu());");
        //    //script.Append(@" function test1(t1,t2){ return t1+t2;};  alert(test1(2,6));");
        //    //script.Append(@" var u = function(){ return 1234;}; ");
        //    //script.Append(@" alert(u());");

        //    //script.Append("var n =2; switch(n){case 1: alert('1'); break; case 2:alert('2') }");
        //    //script.Append(@"var t; alert(t);");
        //    //script.Append(@" var iNum=10; alert(iNum.toString(2));");//测试字符串
        //    //script.Append(" var a=new Array(); a[1.23]=\"test\"; alert(a[1.23]); alert(a.length);");
        //    //script.Append(@" var b=new Array(5,4,3,'first','test,string'); alert(b[0]);");//测试数组
        //    //script.Append(@" alert(null == undefined);");
        //    //script.Append(@" alert(typeof 'aa')");

        //    //script.Append("var n = 0; var obj = {toLocaleString: function() {n++}}; var myArray = [obj, obj, obj]; alert(myArray.toLocaleString());");
        //    script.Append(createTry());
        //    source = script.ToString();

        //    bool isFile = true;
        //    if (isFile)
        //    {
        //        String filename = @"H:\脚本程序\JavaScript\示例\e4x3.js";
        //        ReadFile(cx, shell, filename);
        //    }
        //    else
        //    {
        //        ConsoleFile(cx, shell, source);
        //    }

        //    //Object[] array;
        //    //if (args.Length == 0)
        //    //{
        //    //    array = new Object[0];
        //    //}
        //    //else
        //    //{
        //    //    int length = args.Length - 1;
        //    //    array = new Object[length];
        //    //    Array.Copy(args, 1, array, 0, length);
        //    //}
        //    //Scriptable argsObj = cx.newArray(shell, array);
        //    //shell.defineProperty("arguments", argsObj,
        //    //                     ScriptableObject.DONTENUM);

        //    //Object result = cx.evaluateString(shell, source,
        //    //                                         "<cmd>", 1,
        //    //                                         null);



        //    //Console.ReadKey();
        //    // cx.stringIsCompilableUnit(source);
        }
        public static void ReadFile(Context cx, Shell shell, String filename)
        {
            StreamReader reader = new StreamReader(filename,  Encoding.Unicode);
            String source = reader.ReadToEnd();
            reader.Close();
            Object result = cx.evaluateString(shell, source,
                                                     filename, 1,
                                                     null);
            //  return null;
        }
        public static void ConsoleFile(Context cx, Shell shell, String source)
        {
            Object result = cx.evaluateString(shell, source,
                                                    "<cmd>", 1,
                                                    null);
            Console.WriteLine(Context.toString(result));
        }

        #region 测试
        //StringBuilder s = new StringBuilder();
        //   s.Append("");
        //   return s.ToString();
        public static String createArray()
        {
            StringBuilder s = new StringBuilder();
            //s.Append("var mylist1 = Array();mylist1[0]=1; ");

            //s.Append("var mylist = [1,2,3,'33','uuuw']; mylist[14] = \"bla\"; for(s in mylist){ alert(mylist[s]);}");
            //s.Append(" var g=new Array(3);g[3]=[]; g[3][2]='Test'; alert(g[3][2]); ");
            //s.Append("var hash = { x:10, y:\"foo\" } ; alert(hash['y']);");

            return s.ToString();
        }

        #endregion

        public static String createJson()
        {
            StringBuilder s = new StringBuilder();
            s.Append(" var myJSONObject =  {'bindings': [  ");
            s.Append("{'ircEvent': 'PRIVMSG', 'method': 'newURI', 'regex': '^http://.*'},  ");
            s.Append("{'ircEvent': 'PRIVMSG', 'method': 'deleteURI', 'regex': '^delete.*'},  ");
            s.Append("{'ircEvent': 'PRIVMSG', 'method': 'randomURI', 'regex': '^random.*'}  ");
            s.Append("]  ");
            s.Append("};  alert(myJSONObject.bindings[0].method);");
            return s.ToString();

        }
        public static String createTry()
        {
            StringBuilder s = new StringBuilder();
            //s.Append("try    {   ");
            //s.Append("alert(\"Nested    try    running...\");");
            //s.Append("throw    \"an    error\";   ");
            //s.Append(" }   ");
            //s.Append(" catch(e)    {   ");
            //s.Append("     alert(\"Nested    catch    caught    \"    +    e);   ");
            ////s.Append("    throw    e    +    \"    re-thrown\";   ");
            //s.Append(" }   ");
            //s.Append(" finally    {   ");
            //s.Append("     alert(\"Nested    finally    is    running...\");   ");
            //s.Append(" }　　　　");
            s.Append("var array =   null; try{alert(array[0]);}catch(err){alert(err.name); alert(err.message);} finally{alert('finall.....');}");
            return s.ToString();
        }


        public static void load(Context cx, Scriptable thisObj,
                           Object[] args, Function funObj)
        {
            //Console.WriteLine(args[0]);
            Shell shell = (Shell)getTopLevelScope(thisObj);
            for (int i = 0; i < args.Length; i++)
            {
                shell.processSource(cx, Context.toString(args[i]));
            }
        }

        public static void alert(Context cx, Scriptable thisObj,
                         Object[] args, Function funObj)
        {
            for (int i = 0; i < args.Length; i++)
            {
                if (i > 0)
                    Console.Write(" ");

                // 转换 JavaScript 为 string 类型.
                String s = Context.toString(args[i]);

                Console.WriteLine(s);
            }
           // Console.WriteLine();
        }

        private void processSource(Context cx, String filename)
        {
            if (filename == null)
            {
                String sourceName = "<stdin>";
                int lineno = 1;
                bool hitEOF = false;
                do
                {
                    try
                    {
                        int startline = lineno;
                        if (!isEditor)
                        {//如果不是编辑器，就在这里输出
                            Console.Write("js> ");
                        }
                        String source = "";
                        while (true)
                        {
                            String newline;
                            newline = Console.ReadLine();
                            if (newline == null)
                            {
                                hitEOF = true;
                                break;
                            }
                            source = source + newline + "\n";
                            lineno++;
                            //Console.Write("source::> " + source);
                            if (cx.stringIsCompilableUnit(source))
                            {
                                //Console.Write("js2> ");
                                break;
                            }

                        }
                      //  Console.Write("js::> ");
                        Object result = cx.evaluateString(this, source,
                                                             sourceName, startline,
                                                             null);
                       // Console.Write("js3> ");
                        if (result != Context.getUndefinedValue())
                        {
                            Console.WriteLine(Context.toString(result));
                        }
                        if (isEditor) { Console.WriteLine("js> "); };//如果是编辑器打开
                    }
                    catch (Exception ex) { Console.WriteLine(ex.ToString()); if (isEditor) { Console.WriteLine("js> "); } }//如果是编辑器打开
                } while (!hitEOF);
            }
            else
            {
                StreamReader reader = new StreamReader(Path.GetFullPath(filename),  Encoding.Unicode);
                //try
                //{
                    cx.evaluateReader(this, reader, filename, 1, null);
                //}
                //catch (Exception ex)
                //{
                //    throw ex;
                //}
                //finally
                //{
                //    reader.Close();
                //}
            }
        }

        public override string getClassName()
        {
            return "global";
        }
    }
}
